﻿using FileSynchronization.Helpers;
using FileSynchronization.Model;
using System;

namespace FileSynchronization
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");

            var inputResult = CommandLine.Parser.Default.ParseArguments<UserInput>(args);
            if (inputResult.Errors?.Any() == true)
            {
                return;
            }

            var path = inputResult.Value.Path;
            var watch = inputResult.Value.Watch;
            var url = inputResult.Value.Url;

            // 检查本地目录在不在
            if (Directory.Exists(path) != true)
                throw new NotSupportedException($"没有找到准备同步的目录");

            var api = new FileSubscriptionApi(url);

            if (string.IsNullOrEmpty(watch))
            {
                var allWatchs = api.GetAllWatchs()?.Select(n => new KeyValuePair<string, string>(n.Name, n.Id)).ToList();

                // 选择一个关注对象
                watch = InputHelper.GetUserSelect($"请选择一个关注的项目", allWatchs);
            }

            // 一层层的对比内容，并且准备下载
            DeepSynchronization(api, watch, path);
        }

        static void DeepSynchronization(FileSubscriptionApi api, string id, string rootPath)
        {
            _Synchronization(rootPath);

            void _Synchronization(string path)
            {
                var rPath = Path.GetRelativePath(rootPath, path);

                var dto = api.GetWatchDetail(id, rPath);

                using (new ConsoleColorContent(ConsoleColor.Gray))
                    Console.WriteLine($"Sync {rPath}");

                /*  对比文件
                 *      多余的删掉
                 *      少的直接下载
                 *      存在的对比MD5
                 *          如果不一样删掉下载
                 */

                var oldFiles = Directory.GetFiles(path)?.Select(n => Path.GetFileName(n)).ToArray() ?? new string[0];
                var remoteFiles = dto?.Files ?? new string[0];

                var dels = oldFiles.Except(remoteFiles).ToList();
                foreach (var item in dels)
                {
                    var logicPath = Path.Combine(rPath, item);
                    var filePath = Path.Combine(path, item);

                    using (new ConsoleColorContent(ConsoleColor.Red))
                        Console.WriteLine($"Del {logicPath}");
                    File.Delete(filePath);
                }


                var downs = remoteFiles.Except(oldFiles).ToList();
                foreach (var item in downs)
                {
                    var logicPath = Path.Combine(rPath, item);
                    var filePath = Path.Combine(path, item);

                    using (new ConsoleColorContent(ConsoleColor.Yellow))
                        Console.WriteLine($"Download {logicPath}");
                    var remoteUrl = Path.Combine(dto.Path, item);

                    api.Download(filePath, id, remoteUrl);

                }

                var olds = oldFiles.Intersect(remoteFiles).ToList();
                if (olds.Any())
                {
                    var pageList = PageHelper.Split(olds, 30);
                    foreach (var onePage in pageList)
                    {
                        var fileDetails = api.GetFileDetails(id, rPath, onePage)
                            ?.ToDictionary(n => n.Name, n => n.MD5)
                            ?? new Dictionary<string, string>();

                        foreach (var item in onePage)
                        {
                            var filePath = Path.Combine(path, item);
                            var logicPath = Path.Combine(rPath, item);

                            var localMd5 = FileManager.GetMD5HashFromFile(filePath);

                            if (fileDetails.TryGetValue(item, out var md5) && string.Equals(md5, localMd5, StringComparison.OrdinalIgnoreCase))
                            {
                                using (new ConsoleColorContent(ConsoleColor.Green))
                                    Console.WriteLine($"Check {logicPath}");
                                continue;
                            }

                            using (new ConsoleColorContent(ConsoleColor.Yellow))
                                Console.WriteLine($"Update {logicPath}");
                            var remoteUrl = Path.Combine(dto.Path, item);
                            api.Download(filePath, id, remoteUrl);
                        }
                    }
                }

                /*  对比文件夹
                 *      如果存在多余的文件夹就直接删
                 *      如果其他的文件夹，就尝试创建，并且处理深层次的逻辑
                 */

                var remoteDir = dto.Dirs ?? new string[0];
                var oldDir = Directory.GetDirectories(path)?.Select(n => Path.GetFileName(n)).ToArray() ?? new string[0];

                var delDirs = oldDir.Except(remoteDir).ToList();
                foreach (var item in delDirs)
                {
                    var logicPath = Path.Combine(rPath, item);
                    var filePath = Path.Combine(path, item);

                    using (new ConsoleColorContent(ConsoleColor.Red))
                        Console.WriteLine($"Del {logicPath}");
                    Directory.Delete(filePath, true);
                }

                foreach (var item in remoteDir)
                {
                    var dirPath = Path.Combine(path, item);
                    if (Directory.Exists(dirPath) != true)
                        Directory.CreateDirectory(dirPath);

                    _Synchronization(dirPath);
                }
            }
        }
    }
}
